<!--  -->
<template>
    <span style="width: 100%;">w前进，s后退，a左平移，d右平移，q和e转视角</span>
    <div id="container" style="height:100%;width: 100%;pointer-events: none;"></div>

</template>
<script setup lang="ts">
//three.js机器人移动
import {
    Scene,
    PerspectiveCamera,
    MeshBasicMaterial,

    Mesh,
    WebGLRenderer,
    AxesHelper,
    BufferGeometry,
    BufferAttribute,
    TextureLoader,
    AmbientLight,

    Float32BufferAttribute,
    PointLight,

    Color,

    DoubleSide,
    MeshPhongMaterial,
    RepeatWrapping,
    NearestFilter,
    PlaneGeometry,
    HemisphereLight,
    PointLightHelper,
    SphereGeometry,
    AnimationMixer,
    Object3D,
    Clock,
    DirectionalLight,
    sRGBEncoding,
    Vector3,
    LoopOnce
} from 'three'
import Stats from './jsm/libs/stats.module.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";//动画库
import { onMounted } from 'vue';
import * as dat from "dat.gui";

let scene: any = null;
let camera: any = null;
let rubot: any = null;
let rubot2: any = null;
let renderer: any = null;
let point: any = null;
let gui = false;
let mixer: any = null;
let actions: any = null;
let stats: any = null;
let controls: any = null;
const api = { state: 'Walking' };
const clock = new Clock();
onMounted(() => {
    init();
    wallInitialization();
    upWindowAddEventListener();
    loaderObj();
    keyboardControl();
    animate();

})

const init = () => {
    let container = document.getElementById('container');
    if (!container) {
        return;
    }

    // 创建场景
    scene = new Scene();
    // 创建相机
    camera = new PerspectiveCamera(120, container.clientWidth / container.clientHeight, 0.1, 1000);

    // 设置相机位置
    camera.position.set(0, 5, -5);
    camera.lookAt(0, 0, 0);
    scene.add(camera);


    // 添加坐标系辅助器
    const axesHelper = new AxesHelper(50);
    scene.add(axesHelper);

    //环境光
    var ambient = new AmbientLight(0xffffff, 1);
    scene.add(ambient);
    //点光源
    point = new PointLight(0xff4ae9, 1);
    point.position.set(-8, 8, 8); //点光源位置
    // 点光源距离设置为15
    point.distance = 15;
    // scene.add(point); //点光源添加到场景中
    //点光源变色
    // setInterval(() => {
    //     var hex = Math.random() * 0xffffff;
    //     var color = new Color(hex);
    //     point.color = color;
    // }, 2000);

    // 方向光
    const color = 0xffffff
    const intensity = 1
    const directional = new DirectionalLight(color, intensity)
    directional.position.set(0, 15, 0)
    directional.target.position.set(-5, 0, 0)
    // scene.add(directional)
    // scene.add(directional.target)

    // 光源辅助线
    const helper = new PointLightHelper(point);
    // scene.add(helper)
    //半球光
    const hemisphere = new HemisphereLight(0xb1e1ff, 0xffffff, 1)
    // scene.add(hemisphere)

    // 初始化渲染器
    renderer = new WebGLRenderer();
    renderer.setClearColor(0x66ffcc, 1); //设置背景颜色

    renderer.outputEncoding = sRGBEncoding;
    // 设置渲染器的尺寸
    renderer.setSize(container.clientWidth, container.clientHeight);
    // 将webgl渲染的东西放到body上
    container.appendChild(renderer.domElement);

    // 创建轨道控制器
    controls = new OrbitControls(camera, renderer.domElement);
    // scene.add(controls);

    stats = new Stats();
    // container.appendChild(stats.dom);
}

    let t0 = new Date()
const animate = () => {
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
    const time = clock.getDelta();
    if (mixer) {
        mixer.update(time);
    }

    stats.update();
}

//自适应画面
const upWindowAddEventListener = () => {

    window.addEventListener("resize", () => {
        let container = document.getElementById('container');
        if (!container) {
            return;
        }
        console.log(container.clientWidth, container.clientHeight)
        // 更新摄像头
        camera.aspect = container.clientWidth / container.clientHeight;
        // 更新摄像头的投影矩阵
        camera.updateProjectionMatrix();
        // 更新渲染器
        renderer.setSize(container.clientWidth, container.clientHeight);
        // 设计渲染器的像素比
        renderer.setPixelRatio(window.devicePixelRatio);
        // 将webgl渲染的东西放到body上
        container.appendChild(renderer.domElement);
    });
}


const loaderObj = () => {
    let gltfLoader = new GLTFLoader();
    // let rubot = new FBXLoader();
    gltfLoader.load('../../public/RobotExpressive.glb', (gltf: any) => {
        gltf.encoding = sRGBEncoding;
        rubot = gltf.scene;
        scene.add( rubot );
        
        mixer = new AnimationMixer(rubot);
        actions = mixer.clipAction(gltf.animations[10])//把该物体需要的动画拿出来 移动
        // actions.setLoop( LoopOnce );//只播放一次动画
        // actions.play();
    });

}

//设置四周墙壁
const wallInitialization = () => {
    // 地面 平铺
    let planeSize = 100;
    let loader = new TextureLoader();
    let texturePlan = loader.load('../../public/gezhi.jpg');
    let texturePlan2 = loader.load('../../public/dimianmuwen.png');
    let texturePlan3 = loader.load('../../public/dimiancizhuan.png');
    let texturePlan4 = loader.load('../../public/dimianmabu.png');
    // THREE.RepeatWrapping 纹理重复
    texturePlan.wrapS = RepeatWrapping;
    texturePlan.wrapT = RepeatWrapping;
    texturePlan2.wrapS = RepeatWrapping;
    texturePlan2.wrapT = RepeatWrapping;
    texturePlan3.wrapS = RepeatWrapping;
    texturePlan3.wrapT = RepeatWrapping;
    texturePlan4.wrapS = RepeatWrapping;
    texturePlan4.wrapT = RepeatWrapping;
    // 当一个纹素覆盖大于一个像素时，贴图将如何采样。 THREE.NearestFilter，它将使用最接近的纹素的值。
    texturePlan.magFilter = NearestFilter;
    texturePlan2.magFilter = NearestFilter;
    texturePlan3.magFilter = NearestFilter;
    texturePlan4.magFilter = NearestFilter;
    let repeats = planeSize / 2;
    // 重复次数
    texturePlan.repeat.set(repeats, repeats);
    texturePlan2.repeat.set(repeats, repeats);
    texturePlan3.repeat.set(repeats, repeats);
    texturePlan4.repeat.set(repeats, repeats);
    let planeGeo = new PlaneGeometry(planeSize, planeSize);
    // Phong材质
    let planeMat = new MeshPhongMaterial({ map: texturePlan, side: DoubleSide });
    let planeMat2 = new MeshPhongMaterial({ map: texturePlan2, side: DoubleSide });
    let planeMat3 = new MeshPhongMaterial({ map: texturePlan3, side: DoubleSide });
    let planeMat4 = new MeshPhongMaterial({ map: texturePlan4, side: DoubleSide });
    let meshPlan = new Mesh(planeGeo, planeMat2);
    meshPlan.rotation.x = Math.PI * -0.5;
    scene.add(meshPlan);

    let meshPlan2 = new Mesh(planeGeo, planeMat3);
    let meshPlan3 = new Mesh(planeGeo, planeMat3);
    let meshPlan4 = new Mesh(planeGeo, planeMat4);
    let meshPlan5 = new Mesh(planeGeo, planeMat4);
    let meshPlan6 = new Mesh(planeGeo, planeMat);


    //x轴上两面墙
    meshPlan2.position.x = 50;
    meshPlan2.position.y = 50;
    meshPlan2.rotation.y = Math.PI * -0.5;
    scene.add(meshPlan2);

    meshPlan3.position.x = -50;
    meshPlan3.position.y = 50;
    meshPlan3.rotation.y = Math.PI * -0.5;
    scene.add(meshPlan3);

    //z轴上两面墙
    meshPlan4.position.z = 50;
    meshPlan4.position.y = 50;
    meshPlan4.rotation.z = Math.PI * -0.5;
    scene.add(meshPlan4);

    meshPlan5.position.z = -50;
    meshPlan5.position.y = 50;
    meshPlan5.rotation.z = Math.PI * -0.5;
    scene.add(meshPlan5);

    //顶部
    meshPlan6.position.y = 100;
    meshPlan6.rotation.x = Math.PI * -0.5;
    scene.add(meshPlan6);
}

//设置键盘事件
const keyboardControl = () => {
    window.addEventListener("keydown", (res) => {

        actions.play();//机器人活动

        let keyCode = res.keyCode;
        let position = rubot.position;
        let rotation = rubot.rotation.y;
        switch (keyCode) {
            case 81:        //q
                rubot.rotation.y += 0.1;
                break;
            case 69:        //e
                rubot.rotation.y -= 0.1;
                break;
            case 87:        //w
                if (position.z < 48) {
                    position.x += 0.2 * Math.sin(rotation);
                    position.z += 0.2 * Math.cos(-rotation);
                }
                break;
            case 65:        //a
                if (position.x < 48) {
                    position.x += 0.2 * Math.sin(rotation + Math.PI/2);
                    position.z += 0.2 * Math.cos(-rotation - Math.PI/2);
                }
                break;
            case 68:        //d
                if (position.x > -48) {
                    position.x += 0.2 * Math.sin(rotation - Math.PI/2);
                    position.z += 0.2 * Math.cos(-rotation + Math.PI/2);
                }
                break;
            case 83:        //s
                if (position.z > -48) {
                    position.x -= 0.2 * Math.sin(rotation);
                    position.z -= 0.2 * Math.cos(-rotation);
                }
                break;
            default:
                break;
        }


        //矩阵变换方式计算相机位置 参考http://www.360doc.com/content/22/0302/07/29234429_1019604307.shtml
        //设置相差的位置   相机位置到模型位置的差距
        const relativeCameraOffset = new Vector3(0, 5, -5);
        //通过模型当前位置计算出相差位置
        const cameraOffset = relativeCameraOffset.applyMatrix4( rubot.matrixWorld );
        
        camera.position.x = cameraOffset.x;
        camera.position.y = cameraOffset.y;
        camera.position.z = cameraOffset.z;
        // 始终让相机看向物体
        camera.lookAt(rubot.position);

    });

    window.addEventListener("keyup", (res) => {
        actions.stop();
    });
}


</script>
<style lang='less' scoped>
</style>
